

import os
import sys

import socket;

MSG_OOB = 0x1  # Process data out of band


# The standard FTP server control port
FTP_PORT = 21


# Exception raised when an error or invalid response is received
class Error(Exception): pass
class error_reply(Error): pass  # unexpected [123]xx reply
class error_temp(Error): pass  # 4xx errors
class error_perm(Error): pass  # 5xx errors
class error_proto(Error): pass  # response does not begin with [1-5]


# All exceptions (hopefully) that may be raised here and that aren't
# (always) programming errors on our side
all_errors = (Error, IOError, EOFError)


# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
CRLF = '\r\n'

# The class itself
class FTP:

    debugging = 1
    host = ''
    port = FTP_PORT
    sock = None
    file = None
    welcome = None
    passiveserver = 1

    # Initialization method (called by class instantiation).
    # Initialize host to localhost, port to standard ftp port
    # Optional arguments are host (for connect()),
    # and user, passwd, acct (for login())
    def __init__(self, host='', user='', passwd='', acct='',
                 timeout=900):
        self.host = host;
        self.timeout = timeout
        if host:
            self.connect(host)
            if user:
                self.login(user, passwd, acct)
    def connect(self,host):
        
        self.sock = socket.create_connection((self.host, self.port), self.timeout)
        self.af = self.sock.family
        self.file = self.sock.makefile('rb')
        self.welcome = self.getresp()
        return self.welcome
        
        pass
    
    def login(self,user,passwd):
        
        resp = self.sendcmd('USER ' + user)
        if resp[0] == '3': resp = self.sendcmd('PASS ' + passwd)
        
        pass

    def putline(self, line):
        line = line + CRLF
        self.sock.sendall(line)

    def putcmd(self, line):
        self.putline(line)

    def getline(self):
        line = self.file.readline()
        if not line: raise EOFError
        if line[-2:] == CRLF: line = line[:-2]
        elif line[-1:] in CRLF: line = line[:-1]
        return line

    def getmultiline(self):
        line = self.getline()
        if line[3:4] == '-':
            code = line[:3]
            while 1:
                nextline = self.getline()
                line = line + ('\n' + nextline)
                if nextline[:3] == code and \
                        nextline[3:4] != '-':
                    break
        return line

    def getresp(self):
        resp = self.getmultiline()
        if self.debugging: print '*resp*', resp;
        self.lastresp = resp[:3]
        c = resp[:1]
        if c in ('1', '2', '3'):
            return resp
        if c == '4':
            raise error_temp, resp
        if c == '5':
            raise error_perm, resp
        raise error_proto, resp

    def voidresp(self):
        """Expect a response beginning with '2'."""
        resp = self.getresp()
        if resp[:1] != '2':
            raise error_reply, resp
        return resp


    def sendcmd(self, cmd):
        self.putcmd(cmd)
        return self.getresp()

    def voidcmd(self, cmd):
        self.putcmd(cmd)
        return self.voidresp()



    def makepasv(self):
        
        msg = self.sendcmd('PASV')        
    
        indexleft = msg.find('(') + 1;
        indexright = msg.find(')');
        str_v = msg[indexleft:indexright];
        dict_v = str_v.split(',');
        ip = dict_v[0] + '.' + dict_v[1] + '.' + dict_v[2] + '.' + dict_v[3];
        port = ((int(dict_v[4])) << 8) + int(dict_v[5]);
        return (ip, port);
        

    def ntransfercmd(self, cmd, rest=None):
        
        size = None
        if self.passiveserver:
            host, port = self.makepasv()
            conn = socket.create_connection((host, port), self.timeout)
            try:
                if rest is not None:
                    self.sendcmd("REST %s" % rest)
                resp = self.sendcmd(cmd)
                if resp[0] == '2':
                    resp = self.getresp()
                if resp[0] != '1':
                    raise error_reply, resp
            except:
                conn.close()
                raise
        
        return conn, size

    def transfercmd(self, cmd, rest=None):
        """Like ntransfercmd() but returns only the socket."""
        return self.ntransfercmd(cmd, rest)[0]


    def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
     
        self.voidcmd('TYPE I')
        conn = self.transfercmd(cmd, rest)
        while 1:
            buf = fp.read(blocksize)
            if not buf: break
            conn.sendall(buf)
            if callback: callback(buf)
        conn.close()
        return self.voidresp()

    def storlines(self, cmd, fp, callback=None):
        
        self.voidcmd('TYPE A')
        conn = self.transfercmd(cmd)
        while 1:
            buf = fp.readline()
            if not buf: break
            if buf[-2:] != CRLF:
                if buf[-1] in CRLF: buf = buf[:-1]
                buf = buf + CRLF
            conn.sendall(buf)
            if callback: callback(buf)
        conn.close()
        return self.voidresp()

    def close(self):
        '''Close the connection without assuming anything about it.'''
        if self.file is not None:
            self.file.close()
        if self.sock is not None:
            self.sock.close()
        self.file = self.sock = None

if(__name__ == "__main__"):
    
    f = FTP("192.168.10.148");
    f.login("zhiwang", "123456");
    f.storbinary("STOR /upload/xk1.jpg",open('/home/kelly/xingkong.jpg','rb'));
    
    pass